import * as THREE from 'three'
import { Pane } from 'tweakpane'
import Time from './Utils/Time.js'
import Sizes from './Utils/Sizes.js'
import Stats from './Utils/Stats.js'

import Resources from './Resources.js'
import Renderer from './Renderer.js'
import Camera from './Camera.js'
import Controls from './Controls.js'
import World from './World.js'
import Presets from './Presets.js'

import assets from './assets.js'

export default class Experience
{
    constructor(_options = {})
    {
        window.experience = this

        this.targetElement = _options.targetElement

        if(!this.targetElement)
        {
            console.warn('Missing \'targetElement\' property')
            return
        }

        this.time = new Time()
        this.sizes = new Sizes()
        
        this.setConfig()
        this.setDebug()
        this.setStats()
        this.setScene()
        this.setFog()
        this.setCamera()
        this.setRenderer()
        this.setResources()
        this.setControls()
        this.setWorld()
        this.setPresets()
        this.setIntro()
        
        this.sizes.on('resize', () =>
        {
            this.resize()
        })

        this.update()
    }

    setConfig()
    {
        this.config = {}
    
        // Debug
        this.config.debug = window.location.hash === '#debug'

        // Pixel ratio
        this.config.pixelRatio = Math.min(Math.max(window.devicePixelRatio, 1), 2)

        // Width and height
        const boundings = this.targetElement.getBoundingClientRect()
        this.config.width = boundings.width
        this.config.height = boundings.height || window.innerHeight
    }

    setDebug()
    {
        this.debug = new Pane()
        this.debug.containerElem_.style.width = '320px'
        // this.debug.containerElem_.style.maxHeight = 'calc(100vh - 8px * 2)'
        // this.debug.containerElem_.style.overflowY = 'scroll'
        // this.debug.containerElem_.style.position = 'fixed'
    }

    setStats()
    {
        if(this.config.debug)
        {
            this.stats = new Stats(true)
        }
    }
    
    setScene()
    {
        this.scene = new THREE.Scene()
    }
    
    setFog()
    {
        this.fog = {}
        this.fog.color = '#000000'
        this.fog.instance = new THREE.Fog(this.fog.color, 8.7, 12)
        this.scene.fog = this.fog.instance

        // Debug
        const debugFolder = this.debug.addFolder({
            title: 'fog',
            expanded: false,
        })

        debugFolder
            .addInput(
                this.fog,
                'color',
                { view: 'color' }
            )
            .on('change', () =>
            {
                this.fog.instance.color.set(this.fog.color)
            })
        
        debugFolder
            .addInput(
                this.fog.instance,
                'near',
                { min: 0, max: 20 }
            )
        
        debugFolder
            .addInput(
                this.fog.instance,
                'far',
                { min: 0, max: 20 }
            )
    }

    setCamera()
    {
        this.camera = new Camera()
    }

    setRenderer()
    {
        this.renderer = new Renderer({ rendererInstance: this.rendererInstance })

        this.targetElement.appendChild(this.renderer.instance.domElement)
    }

    setResources()
    {
        this.resources = new Resources(assets)
    }

    setWorld()
    {
        this.world = new World()
    }

    setPresets()
    {
        this.presets = new Presets()
    }

    setIntro()
    {
        this.intro = {}
        this.intro.$element = document.querySelector('.intro')

        window.requestAnimationFrame(() =>
        {
            this.intro.$element.classList.add('is-visible')
        })

        window.setTimeout(() =>
        {
            this.intro.$element.classList.add('is-hidden')
        }, 9000)
    }

    setControls()
    {
        this.controls = new Controls()

        let debugHidden = false
        this.controls.on('debugPressed', () =>
        {
            debugHidden = !debugHidden
            
            if(debugHidden)
            {
                document.documentElement.classList.add('debug-hidden')
            }
            else
            {
                document.documentElement.classList.remove('debug-hidden')
            }
        })
    }

    update()
    {
        if(this.stats)
            this.stats.update()
        
        this.camera.update()

        if(this.world)
            this.world.update()

        if(this.renderer)
            this.renderer.update()

        if(this.controls)
            this.controls.update()

        window.requestAnimationFrame(() =>
        {
            this.update()
        })
    }

    resize()
    {
        // Config
        const boundings = this.targetElement.getBoundingClientRect()
        this.config.width = boundings.width
        this.config.height = boundings.height

        this.config.pixelRatio = Math.min(Math.max(window.devicePixelRatio, 1), 2)

        if(this.camera)
            this.camera.resize()

        if(this.renderer)
            this.renderer.resize()

        if(this.world)
            this.world.resize()
    }

    destroy()
    {
        
    }
}
